# -*- coding: utf-8 -*-
import os
import re
from copy import deepcopy

__version__ = '1.3.2.0'

data_mod =  {
    'name': '',
    'deep': 0,
    'info': '',
    'path': [],
    'dirs': [],
    'files': []
}

def load_dir(dir_path:str, note_map={}, exclude_names=[], ex_pro=False, _path=[], _deep=0):
    """
    加载目录的叶子树
    :dir_path      str    目录路径
    :note_map      dict   注释路径映射表
    :exclude_names list   需要排除的目录名/文件名（支持正则）
    :ex_pro        bool   多功能模式，此模式下解析会用附加其他信息，
                          根据note_map结构选择key-value选false，key-dict则选true
    :*_path        list   路径
    :*_deep        int    深度
    res:
        dict    目录信息
    """
    res = deepcopy(data_mod)
    res['name'] = os.path.split(dir_path)[-1]
    res['path'] = deepcopy(_path)
    #载入注释
    key = '>'.join(res['path'] + [res['name']])
    if not ex_pro:
        res['info'] = note_map.get(key, '')
        res['important'] = 0
    else:
        res['info'] = note_map.get(key, {}).get('info', '')
        res['important'] = note_map.get(key, {}).get('important', 0)
    #继承深度
    res['deep'] = _deep
    _deep += 1
    for root, dirs, files in os.walk(dir_path):
        for dir in dirs:
            _ok = True
            for _re_path in ['^[_\.]'] + exclude_names:
                if not _re_path:
                    continue
                if re.findall('[\\\/:*?"<>\|]', _re_path):
                    # 走正则
                    try:
                        if re.findall(_re_path, dir):
                            _ok = False
                            break
                    except Exception as e:
                        continue
                else:
                    # 走全等
                    if _re_path == dir:
                        _ok = False
                        break
            if not _ok:
                continue
            data = deepcopy(data_mod)
            res['dirs'].append(
                load_dir(
                    os.path.join(dir_path, dir),
                    note_map,
                    exclude_names,
                    ex_pro,
                    _path = res['path'] + [res['name']],
                    _deep = _deep
                )
            )
        for file in files:
            _ok = True
            for _re_path in ['^[_\.]'] + exclude_names:
                if not _re_path:
                    continue    
                if re.findall('[\\\/:*?"<>\|]', _re_path):
                    # 走正则
                    try:
                        if re.findall(_re_path, file):
                            _ok = False
                            break
                    except Exception as e:
                        continue
                else:
                    # 走全等
                    if _re_path == file:
                        _ok = False
                        break             
            if not _ok:
                continue
            data = deepcopy(data_mod)
            data['name'] = file
            data['deep'] = _deep
            data['path'] = _path + [res['name']]
            if not ex_pro:
                data['info'] = note_map.get('>'.join(data['path'] + [data['name']]), '')
            else:
                __d = note_map.get('>'.join(data['path'] + [data['name']]), {})
                data['info'] = __d.get('info', '')
                data['important'] = __d.get('important', 0)
            res['files'].append(data)
        break
    return res

message_mod = {
    'name': '',
    'deep': 0,
    'last': [False],
    'info': '',
    'important': 0
}
def _to_list(dict_map: dict, deep=0, last=[False], ex_pro=False):
    """
    字典转有序列表
    """
    l = []
    data = deepcopy(message_mod)
    data['name'] = dict_map['name']
    data['deep'] = deep
    data['last'] = deepcopy(last)
    data['info'] = dict_map['info']
    data['important'] = dict_map['important']
    l.append(data)
    for dir in dict_map['dirs']:
        l.extend(
            _to_list(
                dir,
                deep+1,
                data['last'] + [(dir == dict_map['dirs'][-1]) and not dict_map['files']],
                ex_pro
            )
        )
    for file in dict_map['files']:
        data = deepcopy(message_mod)
        data['name'] = file['name']
        data['deep'] = deep + 1
        data['last'] = last + [file == dict_map['files'][-1]]
        data['info'] = file['info']
        data['important'] = file['important']
        l.append(data);
    return l

def show_dir(seed_map: dict, note_mark='#', ex_pro=False):
    """
    输出目录构造体
    :seed_map       dict      目录
    :note_mark      string    注释符号标识
    :ex_pro         bool      多功能模式，此模式下解析会用附加其他信息
    res:
        list       目录视图列表
    """
    txts = []
    res = _to_list(seed_map, ex_pro=ex_pro)
    #构造目录树
    for d in res:
        txt = ''
        for bit in d['last'][1:-1]:
            txt += '│   ' if not bit else '   '
        if d['deep'] > 0:
            txt += '├─ ' if not d['last'][-1] else '└─ '
        if d['important'] == 1:
            txt += '★'
        txt += d['name']
        txts.append(txt)
    #推选最大长度
    max_len = 0
    for txt, message in zip(txts, res):
        watch_len = len(txt) - len(message['name']) + \
            (len(message['name']) + len(message['name'].encode('utf-8'))) // 2
        if watch_len > max_len:
            max_len = watch_len
    max_len += 2
    #构造新结构
    new_txts = []
    for txt, message in zip(txts, res):
        watch_len = len(txt) - len(message['name']) + \
            (len(message['name']) + len(message['name'].encode('utf-8'))) // 2
        # 前摇
        new_txt = txt + ' '*(max_len-watch_len)
        # 空格
        if not ex_pro:
            new_txt += " " * 2 * message["deep"]
        else:
            new_txt += " " * (2 * message["deep"] - (1 if message['important'] else 0))
        # 注释
        new_txt += f'{note_mark}{message["info"]}'
        new_txts.append(new_txt)
    return new_txts

def pickup_note_map(txt:str, note_mark='#', ex_pro=False):
    """
    提取目录树种文本
    :txt        string    传入目录视图
    :note_mark  string    注释符号标识
    :ex_pro     bool      多功能模式，此模式下解析会用附加其他信息
    res:
    普通模式下
        dict     路径-注释 的映射图
    多功能模式下
        dict     路径-{
                          'info':   注释,
                          'important': 0/1标记是否重要的
                      }
    """
    txts = txt.split('\n')
    note_map = {}
    note_keys = []
    for line in txts:
        if not line:
            continue
        #_k = note_mark.replace("\\", "\\\\").replace('/', '\/')
        _k = '\\' + '\\'.join(note_mark.split())
        #_k = note_mark
        _res = re.findall(f'^([│├─└ ]*?) *(★*)([\S]+)[ ]*{_k}([\S\s]*?)$', line)
        if not _res:
            continue
        head_txt, important, name, note = _res[0]
        head = (len(head_txt) + 1) // 3
        note_keys = note_keys[0: head]
        note_keys.append(name)
        key = '>'.join(note_keys)
        if not ex_pro:
            note_map[key] = note
        else:
            note_map[key] = {
                'info': note,
                'important': 1 if important else 0
            }
    return note_map


if __name__ == '__main__':
    dir_path = r'F:\work\GoogleImageSpider'
    
    _map = {
        'GoogleImageSpider>app': 'debug',
        'GoogleImageSpider>app>view>api>client.py': '1321 4546'
    }
    res = load_dir(dir_path, _map)
    ex_res = show_dir(res, '//')
    for ex in ex_res:
        print(ex)
    
    _map = pickup_note_map('\n'.join(ex_res),  '//')
    for k,v in _map.items():
        print(k,v)

